#![no_std]
#![no_main]

use arceos_ext::iomap;
use core::time::Duration;
use crab_uvc::{UvcDevice, VideoControlEvent};
use std::string::String;

extern crate axplat_aarch64_dyn;

#[macro_use]
extern crate axstd as std;
#[macro_use]
extern crate log;

mod color_detect;
mod model;
use color_detect::{ColorDetector, DetectorType};
use some_serial::{DataBits, FlowControl, Parity, StopBits, UartConfig, pl011};
use std::thread::sleep;

const UART2_BASE: usize = 0x2800E000;
const UARTCLK: usize = 100_000_000; // 100 MHz

fn create_color_detector_for_format(format: &crab_uvc::VideoFormat) -> ColorDetector {
    let format_str = format!("{:?}", format);
    info!("Creating color detector for format: {format_str}");

    let detector_type = match format.format_type {
        crab_uvc::VideoFormatType::Uncompressed(_) => todo!(),
        crab_uvc::VideoFormatType::Mjpeg => DetectorType::Mjpeg,
        crab_uvc::VideoFormatType::H264 => todo!(),
    };

    let sample_interval = if format_str.contains("320") && format_str.contains("240") {
        4
    } else if format_str.contains("640") && format_str.contains("480") {
        6
    } else if format_str.contains("800") && format_str.contains("600")
        || format_str.contains("1024") && format_str.contains("768")
    {
        8
    } else {
        12
    };
    ColorDetector::new_for_format(sample_interval, detector_type)
}

#[unsafe(no_mangle)]
fn main() {
    let uart_virt = iomap(UART2_BASE.into(), 0x1000).unwrap();
    let mut uart = pl011::new(uart_virt, UARTCLK);
    uart.configure(&UartConfig {
        baud_rate: 57600,
        data_bits: DataBits::Eight,
        stop_bits: StopBits::One,
        parity: Parity::None,
        flow_control: FlowControl::None,
    })
    .unwrap();
    uart.enable();
    let mut tx = uart.try_take_tx().unwrap();
    info!("UART initialized");

    spin_on::spin_on(async {
        println!("Test UVC camera start...");
        let ls = arceos_usb::dev_list().unwrap();
        for dev in &ls {
            info!("  {dev}");
        }
        let mut dev_info = ls
            .into_iter()
            .find(|d| UvcDevice::check(d))
            .expect("No UVC device found");

        let dev = dev_info.open().await.unwrap();
        let mut uvc = UvcDevice::new(dev).await.unwrap();

        let device_info = uvc.get_device_info().await.unwrap();
        info!("Device info: {device_info}");
        let formats = uvc.get_supported_formats().await.unwrap();
        let format = formats.first().cloned().unwrap();
        uvc.set_format(format).await.unwrap();
        let mut stream = uvc.start_streaming().await.unwrap();
        let current_format = stream.vedio_format.clone();

        let mut color_detector = create_color_detector_for_format(&current_format);

        if let Err(e) = uvc
            .send_control_command(VideoControlEvent::BrightnessChanged(100))
            .await
        {
            warn!("Failed to set brightness: {:?}", e);
        }

        loop {
            let batch = stream.recv().await.unwrap();
            for frame in batch {
                match color_detector
                    .detect_and_track_color_change(&frame.data, frame.frame_number as u64)
                {
                    Ok(Some(color_change)) => {
                        info!(
                            "平均RGB: ({}, {}, {}), 当前帧率: {}",
                            color_change.average_color.r,
                            color_change.average_color.g,
                            color_change.average_color.b,
                            color_change.current_fps
                        );
                        info!("当前主题色={}", color_change.new_color);
                        if color_change.new_color.contains("红") {
                            let data: [u8; 14] = [
                                0x05, 0x44, 0x23, 0x18, 0x33, 0x18, 0x00, 0x64, 0x00, 0x64, 0x9d,
                                0x38, 0xf1, 0xcf,
                            ];
                            let mut sent = 0;
                            while sent < data.len() {
                                match tx.write(&data[sent..]) {
                                    Ok(n) if n > 0 => sent += n,
                                    _ => {}
                                }
                            }
                            info!("change Sent to go");
                        }
                    }
                    Ok(None) => {
                        let stats = color_detector.get_statistics();
                        info!(
                            "当前主题色={} 当前帧率={}",
                            stats
                                .current_dominant_color
                                .as_ref()
                                .unwrap_or(&String::from("未知")),
                            stats.current_fps
                        );
                        if stats
                            .current_dominant_color
                            .as_ref()
                            .unwrap_or(&String::from("未知"))
                            .contains("红")
                        {
                            let data: [u8; 14] = [
                                0x05, 0x44, 0x23, 0x18, 0x33, 0x18, 0x00, 0x64, 0x00, 0x64, 0x9d,
                                0x38, 0xf1, 0xcf,
                            ];
                            let mut sent = 0;
                            while sent < data.len() {
                                match tx.write(&data[sent..]) {
                                    Ok(n) if n > 0 => sent += n,
                                    _ => {}
                                }
                            }
                        }
                    }
                    Err(_) => {}
                }
            }
        }
    });
}
